import {
  addDays,
  addMonths,
  addYears,
  startOfMonth,
  endOfMonth,
  startOfDay,
  endOfDay,
  startOfWeek,
  startOfYear,
  endOfYear,
} from "date-fns/esm";

export function generateUUID(): string {
  let d = new Date().getTime(); // 生成时间戳
  const uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
    const r = (d + Math.random() * 16) % 16 | 0;
    d = Math.floor(d / 16);
    return (c === "x" ? r : (r & 0x3) | 0x8).toString(16);
  });
  return uuid;
}
/**
 * 指定日期增加n月
 * @param dateStr 指定日期
 * @param num 月
 * @param type 0:2023-01-30   1：2022-01-30 11:11:11
 * @returns {string}
 * @author: Leo
 */
export function commonAddMouth(dateStr: string | number, num: number | string, type: number | string) {
  let monthNum = 0;
  if (typeof num == "string") {
    monthNum = parseInt(num);
  } else {
    monthNum = num;
  }
  const date = new Date(dateStr);
  //获取原日
  let day: number | string = date.getDate();
  //获取原月份
  // let month = date.getMonth();
  //设置增加月份
  date.setMonth(date.getMonth() + monthNum * 1, 1);
  //获取增加的后的月份
  let Jmonth: number | string = date.getMonth() + 1;
  //获取增加的后的年份
  const Jyear: number | string = date.getFullYear();
  if (Jmonth == 4 || Jmonth == 6 || Jmonth == 9 || Jmonth == 11) {
    //小月
    if (day > 30) {
      day = 30;
    }
  } else if (Jmonth == 2) {
    //2月判断是否闰年
    if ((Jyear % 4 == 0 && Jyear % 100 != 0) || Jyear % 400 == 0) {
      if (day > 29) {
        day = 29;
      }
    }
    if (day > 28) {
      day = 28;
    }
  } else {
    //大月
    if (day > 31) {
      day = 31;
    }
  }
  let tHours: number | string = date.getHours();
  let tMinutes: number | string = date.getMinutes();
  let tSeconds: number | string = date.getSeconds();
  tHours = tHours < 10 ? "0" + tHours : tHours;
  tMinutes = tMinutes < 10 ? "0" + tMinutes : tMinutes;
  tSeconds = tSeconds < 10 ? "0" + tSeconds : tSeconds;
  Jmonth = doHandleMonth(Jmonth);
  day = doHandleMonth(day);
  if (type == "0") {
    return `${Jyear}-${Jmonth}-${day}`;
  }

  return `${Jyear}-${Jmonth}-${day} ${tHours}:${tMinutes}:${tSeconds}`;
}
/**
 *  日或月补0
 * @param month
 * @returns {string}
 */
function doHandleMonth(month: number | string) {
  let m = month;
  if (month.toString().length == 1) {
    m = "0" + month;
  }
  return m;
}
export function getXmonthToday2Stamp(type: number, timeStamp: number) {
  if (timeStamp === 0 || timeStamp === undefined || type === undefined) return 0;
  const str = commonAddMouth(timeStamp, type, 1);
  return new Date(str).getTime();
}

export function beforeDDL(deadLine: number | undefined | null, beforeDDL2Mention: number, mentionUnit: number): number {
  if (
    deadLine === undefined ||
    deadLine === null ||
    deadLine === 0 ||
    beforeDDL2Mention === undefined ||
    isNaN(beforeDDL2Mention) ||
    mentionUnit === undefined
  )
    return 0;
  // if (mentionUnit === 1) return deadLine + beforeDDL2Mention * 1000 * 60 * 60 * 24;
  // if (mentionUnit === 2) return getXmonthToday2Stamp(beforeDDL2Mention, deadLine);
  // if (mentionUnit === 3) return getXmonthToday2Stamp(12 * beforeDDL2Mention, deadLine);
  // console.log(deadLine,beforeDDL2Mention,mentionUnit)
  if (mentionUnit === 1) return addDays(deadLine, beforeDDL2Mention).valueOf();
  if (mentionUnit === 2) return addMonths(deadLine, beforeDDL2Mention).valueOf();
  if (mentionUnit === 3) return addYears(deadLine, beforeDDL2Mention).valueOf();
  return 0;
}

export function computeRangeMonth(start: number, end: number) {
  const monthRangeTimeStamp = [];
  monthRangeTimeStamp.push(start);
  start = addMonths(start, 1).valueOf();
  while (start <= end) {
    monthRangeTimeStamp.push(start);
    start = addMonths(start, 1).valueOf();
  }
  return monthRangeTimeStamp;
}

export function getstartOfDay(date: number) {
  return startOfDay(date).valueOf();
}
export function getEndOfDay(date: number) {
  return endOfDay(date).valueOf();
}
export function getWeek(timeStamp: number) {
  // const endDate = endOfWeek(timeStamp,{weekStartsOn:1})
  const startDate = startOfWeek(timeStamp, { weekStartsOn: 1 }).valueOf();
  const result = new Array<number>();
  for (let i = 0; i < 7; i++) {
    result.push(addDays(startDate, i).getTime());
  }
  return result;
}
export function getMonth(timeStamp: number) {
  // const endDate = endOfWeek(timeStamp,{weekStartsOn:1})
  let startDate = startOfMonth(timeStamp).valueOf();
  const endDate = endOfMonth(timeStamp).valueOf();
  const result = new Array<number>();
  for (let i = startDate; startDate <= endDate; i++) {
    result.push(startDate);
    startDate = addDays(startDate, 1).getTime();
  }
  return result;
}
export function getYear(timeStamp: number) {
  // const endDate = endOfWeek(timeStamp,{weekStartsOn:1})
  let startDate = startOfYear(timeStamp).valueOf();
  const endDate = endOfYear(timeStamp).valueOf();
  const result = new Array<number>();
  for (let i = startDate; startDate <= endDate; i++) {
    result.push(startDate);
    startDate = addMonths(startDate, 1).getTime();
  }
  return result;
}

export function changeTimeUnit(timeStamp: number): string {
  //1、通过“Math.trunc()”方法去除数字的小数部分，保留整数部分；2、通过“Math.round()”方法返回一个数字四舍五入后的整数部分；3、通过“Math.ceil()”方法实现向上取整等等。
  // console.log(timeStamp);
  // type:1变成分钟
  let min = Math.trunc(timeStamp / (60 * 1000));
  let hour = Math.trunc(min / 60);
  min = min - hour * 60;
  let day = Math.trunc(hour / 24);
  hour = hour - day * 24;
  let month = Math.trunc(day / 30);
  day = day - month * 30;
  const year = Math.trunc(month / 12);
  month = month - year * 12;
  return (
    (year === 0 ? "" : year + "年") +
    (month === 0 ? "" : month + "月") +
    (day === 0 ? "" : day + "天") +
    (hour === 0 ? "" : hour + "小时") +
    (min === 0 ? "" : min + "分钟")
  );
}

export function timeToTimestamp(timeStr: string): number {
  const date = new Date(timeStr);
  // 有三种方式获取
  const time1 = date.getTime();
  // var time2 = date.valueOf();
  // var time3 = Date.parse(date);
  // console.log(time1); //1670145353555
  // console.log(time2); //1670145353555
  // console.log(time3); //1670145353000
  return time1;
}

export function timestampToTime(timestamp: number): string {
  if (timestamp === undefined || timestamp === 0) return "";
  // 时间戳为10位需*1000，时间戳为13位不需乘1000
  const date = new Date(timestamp);
  // const Y = date.getFullYear() + "-";
  // const M = (date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1) + "-";
  // const D = (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + " ";
  const h = (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":";
  const m = (date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()) + ":";
  const s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
  return h + m + s;
}

export function timestampToDateTime(timestamp: number | undefined | null): string {
  if (timestamp === 0 || timestamp === undefined || timestamp === null) return "";
  // 时间戳为10位需*1000，时间戳为13位不需乘1000
  const date = new Date(timestamp);
  const Y = date.getFullYear() + "-";
  const M = (date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1) + "-";
  const D = (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + " ";
  const h = (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":";
  const m = (date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()) + ":";
  const s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
  return Y + M + D + h + m + s;
}

export class DateTimeStr {
  timeStamp: number;
  Y: string;
  M: string;
  D: string;
  h: string;
  m: string;
  s: string;
  constructor(timestamp: number) {
    if (!(timestamp === 0 || timestamp === undefined)) {
      // 时间戳为10位需*1000，时间戳为13位不需乘1000
      this.timeStamp = timestamp;
      const date = new Date(timestamp);
      if (date !== undefined && this !== undefined) {
        this.Y = date.getFullYear() + "";
        this.M = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1 + "";
        this.D = date.getDate() < 10 ? "0" + date.getDate() : date.getDate() + "";
        this.h = date.getHours() < 10 ? "0" + date.getHours() : date.getHours() + "";
        this.m = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes() + "";
        this.s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds() + "";
      }
    }
  }
  static getTimeStamp(timeInfo: string) {
    const Y = timeInfo.slice(0, 4) + "-" + timeInfo.slice(4, 6) + "-" + timeInfo.slice(6, 8) + " ";
    const h = timeInfo.slice(8, 10) + ":";
    const m = timeInfo.slice(10, 12) + ":";
    const s = timeInfo.slice(12, 14);
    // console.log(Y + h + m + s)
    // console.log(timestampToDateTime(new Date().getTime()))
    return timeToTimestamp(Y + h + m + s);
  }
  getEndOfDayTimeStamp() {
    return DateTimeStr.getTimeStamp(this.getDayInfo() + "235959");
  }
  getStartOfDayTimeStamp() {
    return DateTimeStr.getTimeStamp(this.getDayInfo() + "000000");
  }
  getYearInfo() {
    return this.Y;
  }
  getMonthInfo() {
    return this.Y + this.M;
  }
  getDayInfo() {
    return this.Y + this.M + this.D;
  }
  getTimeInfo() {
    return this.getDayInfo() + this.h + this.m + this.s;
  }
}

// module.exports = {timeToTimestamp,timestampToTime,timestampToDateTime}
const { stringify, parse } = JSON;
JSON.stringify = function (value, replacer, space) {
  const _replacer =
    typeof replacer === "function"
      ? replacer
      : function (_: any, value: any) {
          return value;
        };
  replacer = function (key, value) {
    value = _replacer(key, value);
    if (value instanceof Set) value = `Set{${stringify([...value])}}`;
    else if (value instanceof Map) value = `Map{${stringify([...value])}}`;
    return value;
  };
  return stringify(value, replacer, space);
};
JSON.parse = function (value, reviver) {
  if (!reviver)
    reviver = function (key, value) {
      if (/Set\{\[.*\]\}/.test(value)) value = new Set(parse(value.replace(/Set\{\[(.*)\]\}/, "[$1]")));
      else if (/Map\{\[.*\]\}/.test(value)) value = new Map(parse(value.replace(/Map\{\[(.*)\]\}/, "[$1]")));
      return value;
    };
  return parse(value, reviver);
};
